//
//  CSTransitioningAnimator.m
//  AXFEightGroup
//
//  Created by ya on 1/2/17.
//  Copyright © 2017 ya. All rights reserved.
//

#import "CSTransitioningAnimator.h"

id selfObject = nil;
NSMethodSignature *signature = nil;


typedef NS_ENUM(NSUInteger, PresentViewControllerState) {
    PresentViewControllerStatePresented = 0,
    PresentViewControllerStateDismissed = 1
};


@interface CSTransitioningAnimator ()<UIViewControllerAnimatedTransitioning>

@property (nonatomic, assign) PresentViewControllerState presentViewControllerState;
@property (nonatomic, copy) AnimationBlockType presentedAnimatorBlock;
@property (nonatomic, copy) AnimationBlockType dismissedAnimatorBlock;

@end


#pragma mark - TransitioningDelegateMethods


@implementation CSTransitioningAnimator (TransitioningDelegateMethods)


- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    self.presentViewControllerState = PresentViewControllerStatePresented;
    return self;
}

- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    self.presentViewControllerState = PresentViewControllerStateDismissed;
    return self;
}


@end


#pragma mark -




@implementation CSTransitioningAnimator

#pragma mark - 初始化


- (instancetype)initWithPresentViewController:(UIViewController *)presentViewController {
    self = [super init];
    if (self) {

        selfObject = self;

        _animtionDuration = 0.25;
        presentViewController.modalPresentationStyle = UIModalPresentationCustom;
        presentViewController.transitioningDelegate  = self;
    }
    return self;
}

+ (instancetype)transitioningAnimatorWithPresentViewController:(UIViewController *)presentViewController {
    return [[CSTransitioningAnimator alloc] initWithPresentViewController:presentViewController];
}


- (void)presentedAnimator:(AnimationBlockType _Nullable)pBlock
        dismissedAnimator:(AnimationBlockType _Nullable)dBlock {
    _presentedAnimatorBlock = pBlock;
    _dismissedAnimatorBlock = dBlock;
}

- (AnimationBlockType)presentedAnimatorBlock {
    if (_presentedAnimatorBlock == nil) {

        __weak __typeof(self)weakSelf = self;
        _presentedAnimatorBlock = ^(id<UIViewControllerContextTransitioning>  _Nonnull transitionContext) {
            UIView *presentedView = [transitionContext viewForKey:UITransitionContextToViewKey];
            UIView *containerView = [transitionContext containerView];
            [containerView addSubview:presentedView];

            presentedView.alpha = 0.0001;
            [UIView animateWithDuration:[weakSelf transitionDuration:transitionContext] animations:^{
                presentedView.alpha = 1.0;
            } completion:^(BOOL finished) {
                [transitionContext completeTransition:YES];
            }];
        };
    }
    return _presentedAnimatorBlock;
}

- (AnimationBlockType)dismissedAnimatorBlock {
    if (_dismissedAnimatorBlock == nil) {
        __weak __typeof(self)weakSelf = self;
        _dismissedAnimatorBlock = ^(id<UIViewControllerContextTransitioning>  _Nonnull transitionContext) {

            UIView *dismissedView = [transitionContext viewForKey:UITransitionContextFromViewKey];
            dismissedView.alpha = 1.0;
            [UIView animateWithDuration:[weakSelf transitionDuration:transitionContext] animations:^{
                dismissedView.alpha = 0.000001;
            } completion:^(BOOL finished) {
                [dismissedView removeFromSuperview];
                [transitionContext completeTransition:YES];
            }];
        };
    }
    return _dismissedAnimatorBlock;
}

#pragma mark -


































#pragma mark - UIViewControllerAnimatedTransitioning


- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return self.animtionDuration;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {

    Class   transitionContextClass   = [transitionContext class];
    SEL     completeTransitionSEL    = @selector(completeTransition:);
    Method  completeTransitionMethod = class_getClassMethod(transitionContextClass,
                                                            completeTransitionSEL);
    IMP     completeTransitionIMP    = class_getMethodImplementation(transitionContextClass,
                                                                     completeTransitionSEL);


    SEL saveSEL = sel_registerName("saveCompleteTransitionSEL:");
    const char *saveType = method_getTypeEncoding(completeTransitionMethod);
    class_addMethod(transitionContextClass,
                    saveSEL,
                    completeTransitionIMP,
                    saveType);

    /// 原有的替换成无效IMP. 走挽救机制.
    SEL     invalidSEL = sel_registerName("invalidCompleteTransitionSEL");
    IMP     invalidIMP = class_getMethodImplementation(transitionContextClass, invalidSEL);
    class_replaceMethod(transitionContextClass,
                        completeTransitionSEL,
                        invalidIMP,
                        NULL);


    SEL     methodSignatureForSelectorSEL    = @selector(methodSignatureForSelector:);
    Method  methodSignatureForSelectorMethod = class_getClassMethod(transitionContextClass,
                                                                    methodSignatureForSelectorSEL);
    class_replaceMethod(transitionContextClass,
                        methodSignatureForSelectorSEL,
                        (IMP)newMethodSignatureForSelectorIMP,
                        method_getTypeEncoding(methodSignatureForSelectorMethod));




    SEL     forwardInvocationSEL    = @selector(forwardInvocation:);
    Method  forwardInvocationMethod = class_getClassMethod(transitionContextClass,
                                                           forwardInvocationSEL);
    class_replaceMethod(transitionContextClass,
                        forwardInvocationSEL,
                        (IMP)newForwardInvocationIMP,
                        method_getTypeEncoding(forwardInvocationMethod));



    switch (self.presentViewControllerState)
    {
        case PresentViewControllerStatePresented:
            self.presentedAnimatorBlock(transitionContext);
            break;

        case PresentViewControllerStateDismissed:
            self.dismissedAnimatorBlock(transitionContext);
            break;

        default:
            break;
    }

//    [transitionContext completeTransition:YES];

}

NSMethodSignature *newMethodSignatureForSelectorIMP(id target, SEL _cmd, SEL targetSEL) {
    return [selfObject methodSignatureForSelector:@selector(beforeCompleteTransitionSEL:)];
}

void newForwardInvocationIMP(id target, SEL _cmd, NSInvocation *invocation) {

    invocation.target = selfObject;
    invocation.selector = @selector(beforeCompleteTransitionSEL:);
    [invocation invoke];


    SEL saveSEL = sel_registerName("saveCompleteTransitionSEL:");
    invocation.target = target;
    invocation.selector = saveSEL;
    [invocation invoke];
}


- (void)beforeCompleteTransitionSEL:(BOOL)didComplete {
    NSLog(@"222222222");
}


#pragma mark -

@end
